package ro.flashbite.loggers
{
	import ro.flashbite.interfaces.IDestroyable;
	import ro.flashbite.loggers.targets.ILoggingTarget;
	import ro.flashbite.loggers.ILogger;
	
	/**
	 * Class used for sending smart outputs; Each logger can output to multiple ILogTarget's
	 * ex: new Logger(), name = "Smart", level = LoggerLevels.DEBUG, message = "Hello!" will trace : "[Smart] [DEBUG] Hello!"
	 *
 	 * v 1.0
	 * 
	 * @author Adrian Barbu
	 */	
	internal final class Logger implements ILogger, IDestroyable, ILoggerProps
	{
		/**
		 * the default max level a logger can send messages. If his level is below, it can transmit 
		 */		
		private var _maxOutputLevel:uint;
		/**
		 * the output name
		 */		
		private var _name:String;
		/**
		 * internal list of output targets to send messages 
		 */		
		private var _outputTargets:Vector.<ILoggingTarget>;
		
		// ================================================================================================================================
		// CONSTRUCTOR
		// ================================================================================================================================
		
		public function Logger(name:String, maxOutputLevel:uint = LoggerLevels.ALL)
		{
			_constructor(name, maxOutputLevel);
		}
		private function _constructor(name:String, maxOutputLevel:uint):void
		{
			_name = name;
			_maxOutputLevel = maxOutputLevel;
			
			_outputTargets = new Vector.<ILoggingTarget>();
		}
		
		// ================================================================================================================================
		// ILogger implementation
		// ================================================================================================================================
		/**
		 * Functions splitted by functionality
		 */		
		public function debug(...message):void { sendMessage(LoggerLevels.DEBUG, message); }
		public function error(...message):void { sendMessage(LoggerLevels.ERROR, message); }

		// ================================================================================================================================
		// ILoggerProps implementation
		// ================================================================================================================================
		
		/**
		 * Getter and setter for _maxOutputLevel property
		 */		
		public function get maxOutputLevel()		: uint 		{ return _maxOutputLevel; 							}
		public function set maxOutputLevel(v:uint)	: void		{ _maxOutputLevel = Math.min(v, LoggerLevels.ALL); 	}
		
		/**
		 * Getter for _name property
		 */		
		public function get name()	: String 	{ return _name;	}
		
		
		/**
		 * Add a target for output to this logger, only if this target isn't already registered
		 * 
		 * @param target : (ILoggingTarget) target to append to internal list
		 */		
		public function addOutputTarget(target:ILoggingTarget):void
		{
			
			if (getLogTargetPosition(target) == -1) _outputTargets.push(target);
			else trace("This target is already registered in this logger");
		}
		/**
		 * Removes a target from this logger 
		 * 
		 * @param target : (ILoggingTarget) the target to remove
		 * @return : (Boolean) true if found and removed, false otherwise
		 */		
		public function removeOutputTarget(target:ILoggingTarget):Boolean
		{
			var pos:int = getLogTargetPosition(target);
			if (pos != -1) {
				_outputTargets.splice(pos, 1);
				return true;
			} else {
				return false;
			}
		}
		
		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		/**
		 * Send a message to all registered _outputTargets
		 * 
		 * @param logLevel : (uint) the level of the message
		 * @param message : (Object) : the data that neeed to be send to his loggingTargets
		 */		
		private function sendMessage(logLevel:uint, ...message):void
		{
			if (requirementsAreMetToLog(logLevel)) {
				for each (var logTarget:ILoggingTarget in _outputTargets)
					logTarget.logMessage(_name, logLevel, message);
			}
		}
		
		/**
		 * Return location of a target in _outputTargets 
		 * 
		 * @param target : (ILoggingTarget) the target to search
		 * @return : (int) -1 if not found, else a index between 0 and _outputTargets.length - 1
		 */		
		private function getLogTargetPosition(target:ILoggingTarget):int { return _outputTargets.indexOf(target); }
		
		/**
		 * Check if this logger can 'send' messages to his logTargets
		 * 
		 * @param logLevel : (uint) the level of the message to create
		 * @return : (Boolean) true if the logLevel is less or equal to _maxOutputLevel and this logger has registered targets
		 */		
		private function requirementsAreMetToLog(logLevel:uint):Boolean { return (logLevel <= _maxOutputLevel && _outputTargets.length != 0); }
		
		// ================================================================================================================================
		// DESTRUCTOR
		// ================================================================================================================================
		
		/**
		 * Proper destroy 
		 */		
		public function destroy():void
		{
			_name = null;
			_outputTargets = null;
		}
	}
}